package cn.monkey.transport.netty.server;

import cn.monkey.transport.netty.TransportConfig;
import cn.monkey.transport.netty.utils.MapUtils;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ServerChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.AttributeKey;

import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;

public class ServerTransportConfig extends TransportConfig<ServerBootstrap, ServerTransportConfig, ServerTransportConfig.Builder, ServerChannel> {
    private EventLoopGroup childGroup = new NioEventLoopGroup();

    private Map<AttributeKey<?>, ?> childChannelAttributes;

    public EventLoopGroup childGroup() {
        return this.childGroup;
    }

    public Map<AttributeKey<?>, ?> childChannelAttributes() {
        return this.childChannelAttributes;
    }

    public ServerTransportConfig() {
        super();
    }

    @Override
    public Builder mutate() {
        return new Builder(this);
    }

    public class Builder extends TransportConfig<ServerBootstrap, ServerTransportConfig, Builder, ServerChannel>.Builder {

        protected Builder(ServerTransportConfig instance) {
            super(instance);
        }

        public Builder childGroup(EventLoopGroup eventLoopGroup) {
            this.instance.childGroup = eventLoopGroup;
            return duplicate();
        }

        public Builder ssl(Supplier<SslHandler> sslHandlerSupplier) {
            if (sslHandlerSupplier == null) {
                throw new NullPointerException();
            }
            Function<ServerBootstrap, ServerBootstrap> sslCustomizer = bootstrap -> {
                SslHandler sslHandler = sslHandlerSupplier.get();
                if (sslHandler == null) {
                    throw new NullPointerException();
                }
                return bootstrap.handler(sslHandler);
            };
            return bootstrapCustomizer(sslCustomizer);
        }

        public Builder childAttributes(Map<AttributeKey<?>, ?> attributes) {
            this.instance.childChannelAttributes = attributes;
            return duplicate();
        }

        public <V> Builder childAttr(AttributeKey<V> key, V val) {
            Objects.requireNonNull(key, "key");
            return childAttributes(MapUtils.updateMap(instance.childChannelAttributes, key, val));
        }
    }
}
